package Utils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 运行时获取泛型类型
 */
public class GenericUtil {
    public static <T> T getSuperclassType(Object obj, int i) {
        try {
            Class<?> aClass = obj.getClass();//先得到类的字节码
            Type genericSuperclass = aClass.getGenericSuperclass();
            if (genericSuperclass instanceof ParameterizedType) {
                ParameterizedType types = (ParameterizedType) genericSuperclass;//抽象类
                Type[] actualTypeArguments = types.getActualTypeArguments();
                Class<T> reponseClass = (Class) actualTypeArguments[i];
                return reponseClass.newInstance();
            } else {
                return null;
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    
    public static <T> T getGenericParameterObject(Class<T> clazz) throws InstantiationException, IllegalAccessException
    {
    	
    	Type type = clazz.getGenericSuperclass();
		Type type2 = (ParameterizedType) type;
		// 获取泛型实际类型参数 如<k,v> --> <Integer,String>这种类型 0 --> Integer
		Type trueType = ((ParameterizedType) type2).getActualTypeArguments()[0];

		@SuppressWarnings("unchecked")
		Class<T> 	entityClass = (Class<T>) trueType;
		return entityClass.newInstance();
    }

    public static <T> T getInterfaceType(Object obj, int i) {
        try {
            Class<?> aClass = obj.getClass();//先得到类的字节码
                /*
                返回表示由此对象表示的类或接口直接实现的接口的类型。
                如果超级接口是一个参数化类型，返回的Type对象必须准确地反映源代码中使用的实际类型参数。代表每个超级界面的参数化类型是在之前没有创建的情况下创建的。有关参数化类型的创建过程的语义，请参阅ParameterizedType的声明。
                如果此对象表示一个类，则返回值是一个包含表示由类实现的所有接口的对象的数组。数组中接口对象的顺序对应于该对象表示的类的声明的implements子句中的接口名称的顺序。在数组类中，接口Cloneable和Serializable按照这个顺序返回。
                如果此对象表示一个接口，则该数组包含表示由该接口直接扩展的所有接口的对象。数组中接口对象的顺序对应于该对象表示的接口声明的extends子句中接口名称的顺序。
                如果此对象表示不实现接口的类或接口，则该方法返回长度为0的数组。
                如果这个对象表示一个原始类型或void，则该方法返回一个长度为0的数组。
                * */
            Type[] types = aClass.getGenericInterfaces();
            ParameterizedType parameterizedType = (ParameterizedType) types[0];
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            Class<T> reponseClass = (Class) actualTypeArguments[i];
            return reponseClass.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Class<?> forName(String className) {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}
